/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.appspot.trick.it.admin.controller;

import com.appspot.trick.it.admin.Constants;
import com.appspot.trick.it.admin.TrickAdmin;
import com.appspot.trick.it.admin.Util;
import com.appspot.trick.it.admin.bind.EditProgressVisibleBinding;
import com.appspot.trick.it.admin.model.ArticleModel;
import com.appspot.trick.it.admin.task.ArticleGetByKeyTask;
import com.appspot.trick.it.admin.task.ArticleUpdateTask;
import com.appspot.trick.it.admin.task.ImagesUpdateTask;
import com.appspot.trick.it.admin.task.LogoImagesUpdateTask;
import com.google.api.services.drive.model.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.FileChooser;

/**
 *
 * @author takahara
 */
public class EditController extends AnchorPane implements Initializable {
    
    private final String INITIAL_TEXT_FIRST = "<!DOCTYPE html>"
            + "<html lang=\"ja\">"
            + "<head>"
            + "</head>"
            + "<body id=\"contents\" contenteditable=\"true\" style=\"overflow-x: hidden;\" onKeyDown=\"if((event.metaKey == true) && (event.keyCode==86)){return false;}\">";
    private final String INITIAL_TEXT_LAST = "</body></html>";
    private final String INITIAL_NULL_TEXT = "<p><br></p>";

    @FXML
    private WebView contentsWebView;
    @FXML
    private WebView descriptionWebView;
    @FXML
    public HBox progressIndicatorHBox;
    @FXML
    private ToggleGroup editToggleGroup;
    @FXML
    private HBox contentsHBox;
    @FXML
    private VBox metaVBox;
    @FXML
    private Label addKeywordLabel;
    @FXML
    private ListView<String> keywordListView;
    @FXML
    private TextField googlePlusKeyTextField;
    @FXML
    private Label logoImageLabel;
    @FXML
    private TextField articleUrlTextField;
    
    private ArticleModel articleModel;
    
    private final ArticleGetByKeyTask articleGetByKeyTask = new ArticleGetByKeyTask();
    private final ArticleUpdateTask articleUpdateTask = new ArticleUpdateTask();
    private final ImagesUpdateTask imagesUpdateTask = new ImagesUpdateTask();
    private final LogoImagesUpdateTask logoImagesUpdateTask = new LogoImagesUpdateTask();
    
    
    /**
     * コンストラクタ
     * @param articleModel
     */
    public EditController(ArticleModel articleModel) {
        this.articleModel = articleModel;
        loadFXML();
    }
    
    /**
     * 初期化メソッド
     */
    private void loadFXML() {
        // ---------------------------------------------------
        // FXMLのロードと設定
        // ---------------------------------------------------
        FXMLLoader fxmlLoader = new FXMLLoader(TrickAdmin.class.getResource("fxml/edit.fxml"));
        fxmlLoader.setRoot(this);
        // 自分自身をコントロールとして設定
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        
        // プログレスの設定
        progressIndicatorHBox.visibleProperty().bind(
                new EditProgressVisibleBinding(
                        articleGetByKeyTask,
                        articleUpdateTask,
                        imagesUpdateTask,
                        logoImagesUpdateTask));
        
        // 記事ロードタスクの初期化
        initLoadTask();
        
        // 貼付けアクションの初期化
        initPasteAction();
        
        // 記事ロードタスクの実行
        articleGetByKeyTask.run(articleModel.getKey());
        
        // 画面遷移の設定
        editToggleGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            @Override
            public void changed(ObservableValue<? extends Toggle> ov,
                    Toggle toggle, Toggle new_toggle) {
                if (new_toggle != null) {
                    String selectUserData = (String)editToggleGroup.getSelectedToggle().getUserData();
                    if(selectUserData.equals("contents")) {
                        contentsHBox.setVisible(true);
                        metaVBox.setVisible(false);
                    }else {
                        contentsHBox.setVisible(false);
                        metaVBox.setVisible(true);
                    }
                    
                }
                
            }
        });
        
        // キーワード追加ラベルの設定
        addKeywordLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                // マウスの左ボタンがクリックされた場合
                if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                    keywordListView.getItems().add("新しいキーワード");
                }
            }
        });
        
        // 記事URLの設定
        String domain = MainController.getInstance().getSiteMstEntity().getDomin();
        if (articleModel.getArticleUrl() != null) {
            String tmp = domain + articleModel.getArticleUrl();
            articleUrlTextField.setText(tmp.replace("https", "http"));
        }
    }
    
    /**
     * 貼付けイベントの初期化
     */
    private void initPasteAction() {
        
        // コンテンツ
        EventHandler contentsWebViewPasteEventHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent t) {
                if(KeyCombination.keyCombination("Shortcut+V").match(t)) {
                    Clipboard clipboard = Clipboard.getSystemClipboard();
                    String text = null;
                    if (clipboard.hasHtml()) {
                        
                        text = Util.htmlTagRemover(clipboard.getHtml()).replace("\"", "\\\"");
                        
                    }else if(clipboard.hasString()) {
                            text = Util.htmlEscape(clipboard.getString()).replace("\"", "\\\"").replace(Constants.SYSTEM_CRLF, "\\n");
                    }
                    
                    if (text != null) {
                        contentsWebView.getEngine().executeScript("var item = \""
                                + text
                                + "\";"
                                + "document.execCommand('insertHTML', false,item);");
                    }
                }
            }
        };
        contentsWebView.addEventHandler(KeyEvent.KEY_RELEASED, contentsWebViewPasteEventHandler);
        
        // コンテンツ
        EventHandler descriptionPasteEventHandler = new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent t) {
                if(KeyCombination.keyCombination("Shortcut+V").match(t)) {
                    Clipboard clipboard = Clipboard.getSystemClipboard();
                    String text = null;
                    if (clipboard.hasHtml()) {
                        
                        text = Util.htmlTagRemover(clipboard.getHtml()).replace("\"", "\\\"");
                        
                    }else if(clipboard.hasString()) {
                            text = Util.htmlEscape(clipboard.getString()).replace("\"", "\\\"").replace(Constants.SYSTEM_CRLF, "\\n");
                    }
                    
                    if (text != null) {
                        descriptionWebView.getEngine().executeScript("var item = \""
                                + text
                                + "\";"
                                + "document.execCommand('insertHTML', false,item);");
                    }
                }
            }
        };
        descriptionWebView.addEventHandler(KeyEvent.KEY_RELEASED, descriptionPasteEventHandler);
    }
    
    /**
     * 保存アクション
     * @throws IOException 
     */
    @FXML
    protected void saveAction() throws IOException {
        
        // コンンテンツ
        if (getContentsHtmlText().trim().equals(INITIAL_NULL_TEXT)) {
            articleModel.setContent(null);
        }else {
            articleModel.setContent(getContentsHtmlText());
        }
        
        // description
        String bodyInnerHTML = (String)descriptionWebView.getEngine().executeScript("document.body.innerHTML");
        String description = Util.HtmlTagRemover(bodyInnerHTML);
        if (description.trim().equals("")) {
            articleModel.setDescription(null);
        }else {
            articleModel.setDescription(description);
        }
        
        // キーワード
        articleModel.setKeyWordList(keywordListView.getItems());
        
        // Google+ Key
        String googlePlusKey = googlePlusKeyTextField.getText();
        if (googlePlusKey.trim().equals("")) {
            articleModel.setGooglePlusKey(null);
        }else {
            articleModel.setGooglePlusKey(googlePlusKey);
        }
        
        // 更新タスクの実行
        articleUpdateTask.run(articleModel);
    }
    
    /**
     * H2タグ追加アクション
     */
    @FXML
    protected void addH2Action() {

        String sauce = "タイトル";
        contentsWebView.getEngine().executeScript("var item = \"<h2>"
                + sauce
                + "</h2>"
                + "\";"
                + "document.execCommand('insertHTML', false,item);");
        
        // 次の<p>タグを追加
        addPTag();
    }
    
    /**
     * H3タグ追加アクション
     */
    @FXML
    protected void addH3Action() {

        String sauce = "タイトル";
        contentsWebView.getEngine().executeScript("var item = \"<h3>"
                + sauce
                + "</h3>"
                + "\";"
                + "document.execCommand('insertHTML', false,item);");
        
        // 次の<p>タグを追加
        addPTag();
    }
    
    /**
     * リストタグ追加アクション
     */
    @FXML
    protected void addListAction() {

        String sauce = "リスト";
        contentsWebView.getEngine().executeScript("var item = \"<ul><li>"
                + sauce
                + "</li></ul>"
                + "\";"
                + "document.execCommand('insertHTML', false,item);");
        
        // 次の<p>タグを追加
        addPTag();
    }
    
    /**
     * HTML追加アクション
     */
    @FXML
    protected void addHTMLAction() {
        final AddHTMLSauceController controller = new AddHTMLSauceController();
        TrickAdmin.getInstance().showAddHTMLSauceStage(controller);
        
        controller.addButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                
                String sauce = controller.sauceTextArea.getText();
                System.out.println(sauce);
                contentsWebView.getEngine().executeScript("var item = \""
                        + sauce.replace("\"", "\\\"").replace(Constants.SYSTEM_CRLF, "\\n")
                        + "\";"
                        + "document.execCommand('insertHTML', false,item);");

                // 次の<p>タグを追加
                addPTag();
                
                TrickAdmin.getInstance().closeAddHTMLSauceStageStage();
            }
        });
    }
    
    /**
     * ソース追加アクション
     */
    @FXML
    protected void addSauceAction() {

        String sauce = "@ここにソースを貼付け@";
        contentsWebView.getEngine().executeScript("var item = \"<hr /><pre>"
                + sauce
                + "</pre><hr />"
                + "\";"
                + "document.execCommand('insertHTML', false,item);");
        
        // 次の<p>タグを追加
        addPTag();
    }
    
    /**
     * 画像追加アクション
     */
    @FXML
    protected void addImageAction() {
        FileChooser fc = new FileChooser();
        fc.setTitle("バナー画像選択");
        fc.setInitialDirectory(new java.io.File(Constants.USER_HOME_DIR_PATH));
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter(Constants.IMAGE_MAIN_FILE_EXTENSION, "*" + Constants.IMAGE_MAIN_FILE_EXTENSION));

        java.io.File importFile = fc.showOpenDialog(TrickAdmin.getInstance().getArticleStage());

        if (importFile != null) {
            imagesUpdateTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    File imageFile =  (File) t.getSource().getValue();
                    String url = Constants.GOOGLE_DRIVE_HOST_BASE_URL + imageFile.getId();
                    
                    // イメージタグの追加
                    contentsWebView.getEngine().executeScript("var item = \"<img src='"
                            + url
                            + "'></img>"
                            + "\";"
                            + "document.execCommand('insertHTML', false,item);");
                    
                    // 次の<p>タグを追加
                    addPTag();
                }
            });

            imagesUpdateTask.run(articleModel, importFile);
        }
    }
    
    /**
     * Pタグの追加
     */
    private void addPTag() {
        contentsWebView.getEngine().executeScript(
                            "var brelement = document.createElement('br');"
                            + "var pelement = document.createElement('p');"
                            + "pelement.appendChild(brelement);"
                            + "document.body.appendChild(pelement);");
    }
    
    /**
     * ロードタスクの初期化
     */
    private void initLoadTask() {
        articleGetByKeyTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {

                articleModel = (ArticleModel) t.getSource().getValue();

                // コンテンツの設定
                String content = articleModel.getContent();
                if (content == null) {
                    contentsWebView.getEngine().loadContent(INITIAL_TEXT_FIRST + INITIAL_NULL_TEXT + INITIAL_TEXT_LAST);
                } else {
                    contentsWebView.getEngine().loadContent(INITIAL_TEXT_FIRST + content + INITIAL_TEXT_LAST);
                }
                
                // description
                String description = articleModel.getDescription();
                if (description == null) {
                    descriptionWebView.getEngine().loadContent(INITIAL_TEXT_FIRST + INITIAL_NULL_TEXT + INITIAL_TEXT_LAST);
                } else {
                    descriptionWebView.getEngine().loadContent(INITIAL_TEXT_FIRST + description + INITIAL_TEXT_LAST);
                }
                
                // キーワードリスト
                if (articleModel.getKeyWordList() != null) {
                    keywordListView.getItems().setAll(articleModel.getKeyWordList());
                }
                
                // Google+ Key
                if (articleModel.getGooglePlusKey() != null) {
                    googlePlusKeyTextField.setText(articleModel.getGooglePlusKey());
                }
                
                // ロゴ画像の初期化
                initLogoImage();
            }
        });
    }
    
    /**
     * バナー画像
     */
    private void initLogoImage() {
        
        ProgressIndicator progressIndicator = new ProgressIndicator();
        progressIndicator.setPrefWidth(20);
        progressIndicator.setPrefHeight(20);
        logoImageLabel.setGraphic(progressIndicator);
        
        
        final ImageView logoImageView = new ImageView();
        logoImageView.setFitHeight(110);
        logoImageView.setPreserveRatio(true);
        
        final Image noBannerImage = new Image(TrickAdmin.class.getResource("images/etc/no-image.jpg").toString());
        
        
        if (articleModel.getLogoImageKey() == null) {
            logoImageView.setImage(noBannerImage);
            logoImageLabel.setGraphic(logoImageView);
                        
        } else {
            final Image bannerImage = new Image(Constants.GOOGLE_DRIVE_HOST_BASE_URL + articleModel.getLogoImageKey(), true);
            bannerImage.progressProperty().addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {

                    if (bannerImage.isError()) {
                        logoImageView.setImage(noBannerImage);
                        logoImageLabel.setGraphic(logoImageView);

                    } else if ((Double) newValue == 1.0 && !bannerImage.isError()) {
                        logoImageView.setImage(bannerImage);
                        logoImageLabel.setGraphic(logoImageView);
                    }
                }
            });
        }
        
        // 画像アップロードイベントの設定
        logoImageLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {

                // マウスの左ボタンがクリックされた場合
                if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                    FileChooser fc = new FileChooser();
                    fc.setTitle("バナー画像選択");
                    fc.setInitialDirectory(new java.io.File(Constants.USER_HOME_DIR_PATH));
                    fc.getExtensionFilters().add(new FileChooser.ExtensionFilter(
                            Constants.IMAGE_MAIN_FILE_EXTENSION, 
                            "*" + Constants.IMAGE_MAIN_FILE_EXTENSION));

                    java.io.File importFile = fc.showOpenDialog(TrickAdmin.getInstance().getArticleStage());

                    if (importFile != null) {
                        try {
                            logoImagesUpdateTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                                @Override
                                public void handle(WorkerStateEvent t) {
                                    initLogoImage();
                                }
                            });
                            
//                            logoImagesUpdateTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
//                                @Override
//                                public void handle(WorkerStateEvent t) {
//                                    logoImagesUpdateTask.getException().printStackTrace();
//                                }
//                            });
                            
                            logoImagesUpdateTask.run(articleModel, importFile);
                            
                            
                        } catch (Exception ex) {
                            Logger.getLogger(EditController.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            }
        });
    }
    
    /**
     * HTML Text の取得
     * @return 
     */
    private String getContentsHtmlText() {
        
        String bodyInnerHTML = (String)contentsWebView.getEngine().executeScript("document.body.innerHTML");
        
        return bodyInnerHTML.replace("<p></p>", "");
    }

}
